package com.andova.image

import android.opengl.GLES30
import com.andova.ext.d
import com.andova.ext.e
import com.andova.ext.v
import java.nio.IntBuffer

fun glesLogExtension() {
    val exts = IntArray(1)
    GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, exts, 0)
    for (i in 0..exts[0]) {
        v("extension[$i]: ${GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i)}")
    }
//    i("extension info [${GLES30.glGetString(GLES30.GL_EXTENSIONS)}]")
}

fun glesLogIntegerv(program: Int, attr: String? = null) {
    val maxDrawBuffer = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_DRAW_BUFFERS, maxDrawBuffer)
    d("max draw buffers -> ${maxDrawBuffer[0]}")
    val maxVertexAttrs = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_ATTRIBS, maxVertexAttrs)
    d("max vertex attributes -> ${maxVertexAttrs[0]}")
    val maxVertexOutCom = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_OUTPUT_COMPONENTS, maxVertexOutCom)
    d("max vertex output components -> ${maxVertexOutCom[0]}")
    val maxFragInCom = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_INPUT_COMPONENTS, maxFragInCom)
    d("max vertex input components -> ${maxFragInCom[0]}")
    val maxVertexUniVec = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, maxVertexUniVec)
    d("max vertex uniform vectors -> ${maxVertexUniVec[0]}")
    val maxFragUniVec = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, maxFragUniVec)
    d("max fragment uniform vectors -> ${maxFragUniVec[0]}")
    val actAttrsNum = IntBuffer.allocate(1)
    GLES30.glGetIntegerv(GLES30.GL_ACTIVE_ATTRIBUTES, actAttrsNum)
    d("active attributes count -> ${actAttrsNum[0]}")
    for (i in 0..actAttrsNum[0]) {
        val size = IntBuffer.allocate(1)
        val type = IntBuffer.allocate(1)
        val name = GLES30.glGetActiveAttrib(program, i, size, type)
        d("attr index $i -> size:$size, type:$type, attr:$name")
    }
    attr?.run { d("attribute %$attr location -> ${GLES30.glGetAttribLocation(program, attr)}") }
}

private fun glesLoadShader(type: Int, glsl: String): Int {
    val shader = GLES30.glCreateShader(type)
    if (shader == 0) {
        e("create shader failure!")
        return GLES30.GL_FALSE
    }
    GLES30.glShaderSource(shader, glsl)
    GLES30.glCompileShader(shader)
    val status: IntBuffer = IntBuffer.allocate(1)
    GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, status)
    if (status[0] != 0) return shader
    e(GLES30.glGetShaderInfoLog(shader))
    GLES30.glDeleteShader(shader)
    return GLES30.GL_FALSE
}

fun glesInitialize(vertexGlsl: String, fragmentGlsl: String): Int {
    val program = GLES30.glCreateProgram()
    if (program == 0) {
        e("create program failure!")
        return GLES30.GL_FALSE
    }
    val vShader = glesLoadShader(GLES30.GL_VERTEX_SHADER, vertexGlsl)
    val fShader = glesLoadShader(GLES30.GL_FRAGMENT_SHADER, fragmentGlsl)
    GLES30.glAttachShader(program, vShader)
    GLES30.glAttachShader(program, fShader)
    GLES30.glLinkProgram(program)
    val status: IntBuffer = IntBuffer.allocate(1)
    GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, status)
    if (status[0] != 0) {
        GLES30.glDetachShader(program, vShader)
        GLES30.glDeleteShader(vShader)
        GLES30.glDetachShader(program, fShader)
        GLES30.glDeleteShader(fShader)
        return program
    }
    e(GLES30.glGetProgramInfoLog(program))
    GLES30.glDetachShader(program, vShader)
    GLES30.glDeleteShader(vShader)
    GLES30.glDetachShader(program, fShader)
    GLES30.glDeleteShader(fShader)
    GLES30.glDeleteProgram(program)
    return GLES30.GL_FALSE
}

class GLES {
    companion object {
        init {
            System.loadLibrary("glcamera")
        }

        external fun glReadPixels(width: Int, height: Int)
    }
}